<template>
	<div class="camera-uploader">
		<van-loading v-if="loading" class="loading"></van-loading>
		<div :class="{ 'camera-box': isBtn, 'camera-box2': true }">
			<div class="border" v-if="isBtn" :style="{ height: borderHeight }"></div>
			<video ref="video" id="video" class="camera-preview" v-if="!captureData && isBtn"></video>
			<img ref="image" :src="captureData" v-show="captureData" class="camera-preview2" />
			<canvas id="canvas" ref="canvas" class="camera-canvas"></canvas>
			<div class="camera-capture" v-if="isBtn">
				<div class="back">
					<img @click="back" src="../../../assets/img-common/back.png" alt="" />
				</div>
				<div class="photo">
					<van-button type="primary" @click="capture"></van-button>
				</div>
				<div class="changePhoto">
					<img @click="switchCamera" src="../../../assets/img-common/change.png" alt="" />
				</div>
			</div>
			<div class="camera-capture" v-if="isUpload">
				<div class="cancel" @click="cancel">取消</div>
				<div class="sure" @click="submit">确认</div>
			</div>
		</div>
	</div>
</template>

<script>
import axios from 'axios'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import { get_ocr, get_pg_infos } from '@/api/PGXT'
export default {
	name: 'CameraUploader',
	components: {},
	props: {
		uploadUrl: {
			type: String,
			required: false
		}
	},
	data() {
		return {
			loading: false,
			test: '',
			isUpload: false,
			isBtn: true,
			isSure: false,
			video: null,
			captureData: null,
			mediaStream: null,
			borderWidth: '300px',
			borderHeight: '100%',
			videoSrc: null
		}
	},
	created() {
		this.borderHeight = screen.width * 0.8 * 1.58 + 'px'
	},
	mounted() {
		this.openCamera()
	},
	methods: {
		back() {
			this.exit()
			this.$router.go(-1)
		},
		openCamera() {
			// navigator.mediaDevices.enumerateDevices() 检查设备是否可用
			// visibilitychange 检测应用程序是否处于前台或后台
			console.log('初始化')
			console.log('video', navigator.mediaDevices.getUserMedia)
			// 老的浏览器可能根本没有实现 mediaDevices，所以我们可以先设置一个空的对象
			if (navigator.mediaDevices === undefined) {
				navigator.mediaDevices = {}
			}
			if (navigator.mediaDevices.getUserMedia === undefined) {
				navigator.mediaDevices.getUserMedia = function (constraints) {
					// 首先，如果有 getUserMedia 的话，就获得它
					var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia
					// 一些浏览器根本没实现它 - 那么就返回一个 error 到 promise 的 reject 来保持一个统一的接口
					if (!getUserMedia) {
						return Promise.reject(
							new Error('getUserMedia is not implemented in this browser')
						)
					}
					// 否则，为老的 navigator.getUserMedia 方法包裹一个 Promise
					return new Promise(function (resolve, reject) {
						getUserMedia.call(navigator, constraints, resolve, reject)
					})
				}
			}
			navigator.mediaDevices
				.getUserMedia({
					video: {
						// width: { ideal: 640 },
						// height: { ideal: 480 },
						facingMode: this.isFrontCamera ? 'user' : 'environment',
						// aspectRatio: 16 / 9
						// frameRate: { ideal: 10, max: 15 }
						// width: { min: 1024, ideal: 1280, max: 1920 },
						// height: { min: 776, ideal: 720, max: 1080 }
					},
					audio: false
				})
				.then((stream) => {
					this.mediaStream = stream
					this.video = this.$refs.video
					// 旧的浏览器可能没有 srcObject
					if ('srcObject' in this.video) {
						this.video.srcObject = stream
					} else {
						// 防止在新的浏览器里使用它，应为它已经不再支持了
						this.video.src = window.URL.createObjectURL(stream)
					}
					const video = document.getElementById('video');
					const canvas = document.getElementById('canvas')
					const ctx = canvas.getContext('2d')
					const pixelRatio = window.devicePixelRatio || 1;
					function draw() {
						ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
						requestAnimationFrame(draw)
					}
					this.video.addEventListener('loadedmetadata', () => {
						console.log('videoW', this.video.videoWidth)
						console.log('videoH', this.video.videoHeight)
						this.video.play()
						canvas.width = this.video.videoWidth * pixelRatio;
						canvas.height = this.video.videoHeight * pixelRatio;
						requestAnimationFrame(draw)
					})
				})
				.catch((err) => {
					console.log('打开相机失败：' + err)
				})
		},
		switchCamera() {
			// 切换摄像头状态
			this.isFrontCamera = !this.isFrontCamera
			// 如果摄像头已经打开，重新调用getUserMedia()方法获取视频流
			if (this.mediaStream) {
				this.mediaStream.getTracks().forEach((track) => track.stop())
				this.mediaStream = null
				if (navigator.mediaDevices === undefined) {
					navigator.mediaDevices = {}
				}
				navigator.mediaDevices
					.getUserMedia({
						video: {
							width: { ideal: 640 },
							height: { ideal: 480 },
							facingMode: this.isFrontCamera ? 'user' : 'environment'
						},
						audio: false
					})
					.then((stream) => {
						this.mediaStream = stream
						this.video.srcObject = stream
						this.video.addEventListener('loadedmetadata', () => {
							this.video.play()
						})
					})
					.catch((err) => {
						console.log('切换摄像头失败：' + err.message)
					})
			}
		},
		exit() {
			if (this.mediaStream) {
				this.mediaStream.getTracks().forEach((track) => track.stop())
			}
			this.captureData = ''
			this.isBtn = true
			this.isUpload = false
			this.video.pause()
			this.video.src = ''
		},
		cancel() {
			this.exit()
			this.$emit('updateComponents')
		},
		imageSize(base64Str) {
			const indexBase64 = base64Str.indexOf('base64,')
			if (indexBase64 < 0) return -1
			const str = base64Str.substr(indexBase64 + 6)
			return (str.length * 0.75).toFixed(2)
		},
		submit() {
			this.loading = true
			// 获取裁剪后的图片的 base64 格式
			const croppedCanvas = this.cropper.getCroppedCanvas({
				// width: 100,
				// height: 196,
				// left: 600,
				// top: 948
			})
			const croppedBase64 = croppedCanvas.toDataURL()
			let self = this
			let img = new Image()
			img.src = croppedBase64
			img.onload = function () {
				let newBase64 = self.compress(img)
				//   if (dataURL.length <= 500 * 1024) {
				// console.log('压缩后', newBase64)
				// console.log('压缩后大小', newBase64.length)
				// console.log('压缩后大小2', self.imageSize(newBase64))
				//   } else {
				//   }
				// self.captureData = newBase64
				self.getIdCardByOCR(newBase64)
			}
		},
		async getPGInfos(idCard) {
			let res = await get_pg_infos({ idNumber: idCard })
			console.log('res', res)
			if (res.succeed) {
				this.$store.commit('user/SET_ID', res.data.assessHandleId)
				this.$router.push({
					path: '/PG',
					query: {
						isDetail: ''
					}
				})
			} else {
				this.$toast.fail(res.msg)
				this.cancel()
			}
			this.loading = false
		},
		async getIdCardByOCR(base64) {
			let res = await get_ocr({ ocrType: 'idcard', imgString: base64 })
			console.log(res)
			if (res.status == 1 && res.id) {
				this.getPGInfos(res.id)
			} else {
				this.$toast.fail('身份证信息扫描失败，请重新拍照上传！')
				this.cancel()
			}
			this.loading = false
		},
		afterRead(file) {
			const canvas = this.$refs.canvas
			const ctx = canvas.getContext('2d')
			const video = this.$refs.video
			canvas.width = video.videoWidth
			canvas.height = video.videoHeight
			ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
			canvas.toBlob(
				(blob) => {
					const formData = new FormData()
					formData.append('file', blob, file.name)
					axios
						.post(this.uploadUrl, formData, {
							headers: {
								'Content-Type': 'multipart/form-data'
							}
						})
						.then((res) => {
							this.$emit('upload-success', res.data)
						})
						.catch((err) => {
							console.log(err)
						})
				},
				'image/jpeg',
				0.9
			)
		},
		upload(file) {
			return new Promise((resolve) => {
				resolve()
			})
		},
		getImgByCropper() {
			let self = this
			// 初始化 Cropper.js
			this.cropper = new Cropper(this.$refs.image, {
				// aspectRatio: 1 / 1.58, //默认比例
				// autoCropArea: 0.8,
				cropBoxResizable: true,
				cropBoxMovable: true,
				dragMode: 'none',
				ready: function () {
					self.captureData = ''
					self.loading = false
					self.isUpload = true
				},
				crop: (event) => {
					console.log(event)
				}
			})
		},
		handleImg(dataURL) {
			let self = this
			self.captureData = dataURL
			setTimeout(() => {
				self.getImgByCropper()
			}, 1000)
			// console.log('压缩前', dataURL)
		},
		compress(img) {
			// console.log('img',img);
			let canvas = document.createElement('canvas')
			let ctx = canvas.getContext('2d')
			//瓦片canvas
			let tCanvas = document.createElement('canvas')
			let tctx = tCanvas.getContext('2d')
			// let initSize = img.src.length;
			let width = img.width
			let height = img.height
			//如果图片大于四百万像素，计算压缩比并将大小压至400万以下
			let ratio
			if ((ratio = (width * height) / 4000000) > 1) {
				// console.log("大于400万像素");
				ratio = Math.sqrt(ratio)
				width /= ratio
				height /= ratio
			} else {
				ratio = 1
			}
			canvas.width = width
			canvas.height = height
			// 铺底色
			ctx.fillStyle = '#fff'
			ctx.fillRect(0, 0, canvas.width, canvas.height)
			//如果图片像素大于100万则使用瓦片绘制
			let count
			if ((count = (width * height) / 1000000) > 1) {
				count = ~~(Math.sqrt(count) + 1) //计算要分成多少块瓦片
				//            计算每块瓦片的宽和高
				let nw = ~~(width / count)
				let nh = ~~(height / count)
				tCanvas.width = nw
				tCanvas.height = nh
				for (let i = 0; i < count; i++) {
					for (let j = 0; j < count; j++) {
						tctx.drawImage(
							img,
							i * nw * ratio,
							j * nh * ratio,
							nw * ratio,
							nh * ratio,
							0,
							0,
							nw,
							nh
						)
						ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh)
					}
				}
			} else {
				ctx.drawImage(img, 0, 0, width, height)
			}
			//进行最小压缩
			let ndata = canvas.toDataURL('image/jpeg', 0.6)
			tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0
			return ndata
		},
		capture() {
			this.loading = true
			this.isBtn = false
			const canvas = this.$refs.canvas
			const ctx = canvas.getContext('2d')
			const video = this.$refs.video
			canvas.width = video.videoWidth
			canvas.height = video.videoHeight
			ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
			const dataURL = canvas.toDataURL('image/jpeg', 0.9)
			this.cropper = null
			// 压缩
			this.handleImg(dataURL)
		}
	}
}
</script>

<style lang="less" scoped>
.loading {
	position: fixed;
	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
	z-index: 99999;
}
.camera-uploader {
	display: flex;
	flex-direction: column;
	align-items: center;
	height: 100vh;
}

.camera-box2 {
	position: relative;
	width: 100%;
	height: 100%;
	display: flex;
	align-items: center;
	background-color: #000;
	// padding-bottom: 100%;
}
.border {
	z-index: 99;
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 80%;
	height: 80%;
	border: 5px dashed #fff;
	box-sizing: border-box;
}

.camera-preview {
	width: 100%;
	display: none;
	// height: 100%;
	// transform: rotate(90deg);
	// object-fit: cover;
}

.camera-preview2 {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 100%;
	// height: 100%;
}

.camera-canvas {
	width: 100%;
	// display: none;
	// z-index: 9999;
	// position: fixed;
	// left: 0;
	// top: 0;
}

// .camera-box:before {
// 	content: '';
// 	z-index: 99;
// 	position: absolute;
// 	top: 50%;
// 	left: 50%;
// 	transform: translate(-50%, -50%);
// 	width: 600px;
// 	height: 948px;
// 	border: 5px dashed red;
// 	box-sizing: border-box;
// }

.camera-box:after {
	content: '请将身份证放置在边框内';
	z-index: 99;
	position: absolute;
	top: 63%;
	left: 20%;
	transform: rotate(90deg) translateX(-50%);
	color: #ffffff76;
	font-size: 42px;
}

.camera-button {
	margin-top: 20px;
	width: 150px;
	height: 50px;
	border-radius: 25px;
	background-color: #ff6a3d;
	display: flex;
	justify-content: center;
	align-items: center;
	color: #fff;
	font-size: 16px;
	font-weight: bold;
}
.camera-capture {
	position: absolute;
	width: 100%;
	height: 100px;
	bottom: 5%;
	left: 50%;
	transform: translateX(-50%);
	z-index: 9;
	.back {
		width: 150px;
		height: 150px;
		position: absolute;
		left: 10%;
		display: flex;
		align-items: center;
		justify-content: center;
		img {
			width: 60px;
			height: 60px;
		}
	}
	.photo {
		width: 150px;
		height: 150px;
		position: absolute;
		left: 50%;
		transform: translateX(-50%);
		background-color: #ffffff;
		border-radius: 100%;
		display: flex;
		justify-content: center;
		align-items: center;
		.van-button {
			padding: 0px;
			border-color: #fff;
			width: 90%;
			height: 90%;
			border-radius: 100px;
			background-color: #9b9b9b5e;
			display: flex;
			align-items: center;
			justify-content: center;
		}
	}
	.changePhoto {
		width: 150px;
		height: 150px;
		position: absolute;
		right: 10%;
		display: flex;
		align-items: center;
		justify-content: center;
		img {
			width: 60px;
			height: 60px;
		}
	}
	.cancel {
		position: absolute;
		left: 20%;
		color: #fff;
		font-size: 36px;
	}
	.sure {
		position: absolute;
		left: 70%;
		color: #fff;
		font-size: 36px;
	}
	div {
		margin: 0 10px;
	}
}
</style>
